notifications: per-mission terminal-event notifications#113
Merged
Conversation
Add an opt-in mission notification system that delivers mission_completed /
mission_failed / mission_stopped to a gateway and/or the command center.
- config: per-mission `notification { gateway {} command_center {} }` block;
each channel takes `enabled` + optional `events` filter; gateway-only
`channel` override. No block => no notifications. Cross-block validation
rejects a gateway channel with no configured gateway.
- notification: Dispatcher fans a Record out to enabled, event-matching sinks.
- gateway: Manager.Notify + NotifySink forward to the gateway subprocess.
- wsbridge: command-center sink (TypeNotification envelope, no-op when no CC
connected); dispatch wired into the mission terminal path. mission_completed
carries aggregated task outputs (Runner.CollectOutputs).
HITL is untouched. Depends on new squadron-gateway-sdk (OnNotification) and
squadron-wire (TypeNotification) versions — bump before merge.
readPump/writePump read the shared c.ws field on every op, so on reconnect connectToURL swapped in a new socket and started a second pair of pumps without stopping the old ones — the stale writePump then wrote to the new socket concurrently with the new writePump, panicking with "concurrent write to websocket connection". Each connection now owns its handles: pumps capture their conn (and a per-connection quit/done) as locals, connectToURL signals the previous connection's pumps to stop and closes the old socket under a new connMu before swapping in the new one, and Close tears down under the same lock. Adds a reconnect regression test and makes the wsbridge test mock thread-safe so the suite is race-clean.
Per-channel config is now: `enabled` (bool, defaults true — set false to keep a channel configured but turn delivery off) plus a required, explicit `events` list. Valid event values are mission_completed, mission_failed, mission_stopped, or "all" (expands to every terminal event). Both gateway and command_center use the same shape; channel is the only gateway-only extra. Omitting `events` is now a validation error rather than silently defaulting to all — delivery is always explicit.
Add missions/notifications.mdx covering the per-mission `notification` block — gateway + command_center channels, the enabled toggle (default true), the required explicit `events` list with the "all" shorthand, the gateway-only channel override, what each terminal event carries, and validation rules. Register it in the missions nav and cross-link from the gateways and command_center config pages.
mission_stopped is no longer a notification event: it's removed from the valid events set (so "all" expands to mission_completed + mission_failed), and a user-initiated stop no longer dispatches a notification. mission_stopped remains a normal mission-lifecycle event on the command-center event stream — this only affects the notification feature. Docs + tests updated.
mlund01
commented
Jun 14, 2026
Per PR feedback, remove the per-task output aggregation from notifications: a mission_completed notification is now just a completion notice (no Outputs). Drops Runner.CollectOutputs and the Outputs plumbing on the dispatch record and both sinks. Docs: remove the unnecessary HITL aside and the in-memory note, and document that a gateway channel override accepts a channel name (not just an id).
When a gateway is configured, agents get a builtins.gateway.post tool that posts a message (with an optional channel name/id override) to the gateway's external system via the new SDK PostMessage RPC. The gateway Manager satisfies aitools.GatewayBridge directly; the bridge threads through the runner and agent options alongside the human-input bridge. The tool is only a valid reference when a gateway block is present (rejected by squadron verify otherwise) and is hidden from the command-center tool list when no gateway is configured. Tests + gateways doc added.
The gateway Manager fetches the gateway's MessageToolSpec on startup; the GatewayBridge exposes its description + JSON Schema, and builtins.gateway.post surfaces them to the LLM (raw-schema passthrough) and forwards the agent's raw payload to the gateway. Lets each gateway define its own rich-message shape (text, embeds/blocks, attachments). Tests + gateways doc updated.
mlund01
commented
Jun 15, 2026
The post tool now owns an `attachments` field (injected into the gateway
schema) taking {slot, path} references into the mission's memory/scratchpad.
Squadron resolves each, reads the bytes (25 MiB/file cap), strips them from
the gateway payload, and ships them to the gateway to upload. Eliminates the
SSRF surface of fetching arbitrary model-chosen URLs. Bump SDK to v0.0.3.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Opt-in mission notification system: delivers
mission_completed/mission_failed/mission_stoppedto a gateway and/or the command center. HITL is untouched.Per-mission HCL:
notification { gateway {} command_center {} }; each channel takesenabled+ optionaleventsfilter; gateway-onlychanneloverride. No block ⇒ no notifications. Cross-block validation rejects a gateway channel with no configured gateway. (command_center has no validation — it no-ops when no CC is connected.)Dispatcherfans aRecordto enabled, event-matching sinks.Manager.Notify+NotifySinkforward to the gateway subprocess (with the per-mission channel override).TypeNotification, no-op when no CC connected); dispatch wired into the mission terminal path.mission_completedcarries aggregated task outputs viaRunner.CollectOutputs().Tests: config parsing/validation, dispatcher fan-out/filtering,
Manager.Notify.Depends on new versions of:
OnNotification) — gateway: add OnNotification RPC squadron-gateway-sdk#3TypeNotification) — protocol: add TypeNotification message + NotificationPayload squadron-wire#12go.modstill pins the old versions, so this won't build until those are tagged and therequirelines are bumped. Intentional — opened for code review. Noreplacedirectives (per repo policy).